{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Examples\n",
    "\n",
    "This example use randoms values for wind speed and direction(ws and wdnotebooks/windrose_sample_poitiers_csv.ipynb\n",
    "variables). In situation, these variables are loaded with reals values\n",
    "(1-D array), from a database or directly from a text file.\n",
    "See [this notebook](https://github.com/python-windrose/windrose/blob/master/notebooks/windrose_sample_poitiers_csv.ipynb) for an example of real data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "N = 500\n",
    "ws = np.random.random(N) * 6\n",
    "wd = np.random.random(N) * 360"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A stacked histogram with normed (displayed in percent) results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from windrose import WindroseAxes\n",
    "\n",
    "ax = WindroseAxes.from_ax()\n",
    "ax.bar(wd, ws, normed=True, opening=0.8, edgecolor=\"white\")\n",
    "ax.set_legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Another stacked histogram representation, not normed, with bins limits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ax = WindroseAxes.from_ax()\n",
    "ax.box(wd, ws, bins=np.arange(0, 8, 1))\n",
    "ax.set_legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A windrose in filled representation, with a controlled colormap."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib import cm\n",
    "\n",
    "ax = WindroseAxes.from_ax()\n",
    "ax.contourf(wd, ws, bins=np.arange(0, 8, 1), cmap=cm.hot)\n",
    "ax.set_legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Same as above, but with contours over each filled region..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ax = WindroseAxes.from_ax()\n",
    "ax.contourf(wd, ws, bins=np.arange(0, 8, 1), cmap=cm.hot)\n",
    "ax.contour(wd, ws, bins=np.arange(0, 8, 1), colors=\"black\")\n",
    "ax.set_legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ...or without filled regions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ax = WindroseAxes.from_ax()\n",
    "ax.contour(wd, ws, bins=np.arange(0, 8, 1), cmap=cm.hot, lw=3)\n",
    "ax.set_legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After that, you can have a look at the computed values used to plot the\n",
    "windrose with the `ax._info` dictionary :\n",
    "\n",
    "- `ax._info['bins']` :\n",
    "  list of bins (limits) used for wind speeds. If not set in the call, bins\n",
    "  will be set to 6 parts between wind speed min and max.\n",
    "- `ax._info['dir']` : list of directions \"boundaries\" used to compute the\n",
    "  distribution by wind direction sector. This can be set by the nsector\n",
    "  parameter (see below).\n",
    "- `ax._info['table']` : the resulting table of\n",
    "  the computation. It's a 2D histogram, where each line represents a wind\n",
    "  speed class, and each column represents a wind direction class.\n",
    "\n",
    "So, to know the frequency of each wind direction, for all wind speeds, do:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ax.bar(wd, ws, normed=True, nsector=16)\n",
    "table = ax._info[\"table\"]\n",
    "wd_freq = np.sum(table, axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and to have a graphical representation of this result:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "direction = ax._info[\"dir\"]\n",
    "wd_freq = np.sum(table, axis=0)\n",
    "\n",
    "plt.bar(np.arange(16), wd_freq, align=\"center\")\n",
    "xlabels = (\n",
    "    \"N\",\n",
    "    \"\",\n",
    "    \"N-E\",\n",
    "    \"\",\n",
    "    \"E\",\n",
    "    \"\",\n",
    "    \"S-E\",\n",
    "    \"\",\n",
    "    \"S\",\n",
    "    \"\",\n",
    "    \"S-O\",\n",
    "    \"\",\n",
    "    \"O\",\n",
    "    \"\",\n",
    "    \"N-O\",\n",
    "    \"\",\n",
    ")\n",
    "xticks = np.arange(16)\n",
    "plt.gca().set_xticks(xticks)\n",
    "plt.gca().set_xticklabels(xlabels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition of all the standard pyplot parameters, you can pass special\n",
    "parameters to control the windrose production. For the stacked histogram\n",
    "windrose, calling help(ax.bar) will give :\n",
    "`bar(self, direction, var, **kwargs)` method of\n",
    "`windrose.WindroseAxes` instance Plot a windrose in bar mode. For each\n",
    "var bins and for each sector, a colored bar will be draw on the axes.\n",
    "\n",
    "Mandatory:\n",
    "\n",
    "- `direction` : 1D array - directions the wind blows from, North centred\n",
    "- `var` : 1D array - values of the variable to compute. Typically the wind speeds\n",
    "\n",
    "Optional:\n",
    "\n",
    "- `nsector` : integer - number of sectors used to compute\n",
    "  the windrose table. If not set, nsectors=16, then each sector will be\n",
    "  360/16=22.5°, and the resulting computed table will be aligned with the\n",
    "  cardinals points.\n",
    "- `bins` : 1D array or integer - number of bins, or a\n",
    "  sequence of bins variable. If not set, bins=6 between min(var) and\n",
    "  max(var).\n",
    "- `blowto` : bool. If True, the windrose will be pi rotated,\n",
    "  to show where the wind blow to (useful for pollutant rose).\n",
    "- `colors` : string or tuple - one string color (`'k'` or\n",
    "  `'black'`), in this case all bins will be plotted in this color; a\n",
    "  tuple of matplotlib color args (string, float, rgb, etc), different\n",
    "  levels will be plotted in different colors in the order specified.\n",
    "- `cmap` : a cm Colormap instance from `matplotlib.cm`. - if\n",
    "  `cmap == None` and `colors == None`, a default Colormap is used.\n",
    "- `edgecolor` : string - The string color each edge bar will be plotted.\n",
    "  Default : no edgecolor\n",
    "- `opening` : float - between 0.0 and 1.0, to\n",
    "  control the space between each sector (1.0 for no space)\n",
    "- `mean_values` : Bool - specify wind speed statistics with\n",
    "  direction=specific mean wind speeds. If this flag is specified, var is\n",
    "  expected to be an array of mean wind speeds corresponding to each entry\n",
    "  in `direction`. These are used to generate a distribution of wind\n",
    "  speeds assuming the distribution is Weibull with shape factor = 2.\n",
    "- `weibull_factors` : Bool - specify wind speed statistics with\n",
    "  direction=specific weibull scale and shape factors. If this flag is\n",
    "  specified, var is expected to be of the form \\[\\[7,2\\], ...., \\[7.5,1.9\\]\\]\n",
    "  where var\\[i\\]\\[0\\] is the weibull scale factor and var\\[i\\]\\[1\\] is the shape\n",
    "  factor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Probability density function (pdf) and fitting Weibull distribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from windrose import WindAxes\n",
    "\n",
    "ax = WindAxes.from_ax()\n",
    "bins = np.arange(0, 6 + 1, 0.5)\n",
    "bins = bins[1:]\n",
    "ax, params = ax.pdf(ws, bins=bins)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Optimal parameters of Weibull distribution can be displayed using"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"{params=}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overlay of a map"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This example illustrate how to set an windrose axe on top of any other axes. Specifically,\n",
    "overlaying a map is often useful.\n",
    "It rely on matplotlib toolbox inset_axes utilities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cartopy.crs as ccrs\n",
    "import cartopy.io.img_tiles as cimgt\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from mpl_toolkits.axes_grid1.inset_locator import inset_axes\n",
    "\n",
    "import windrose\n",
    "\n",
    "ws = np.random.random(500) * 6\n",
    "wd = np.random.random(500) * 360\n",
    "\n",
    "minlon, maxlon, minlat, maxlat = (6.5, 7.0, 45.85, 46.05)\n",
    "\n",
    "proj = ccrs.PlateCarree()\n",
    "fig = plt.figure(figsize=(12, 6))\n",
    "# Draw main ax on top of which we will add windroses\n",
    "main_ax = fig.add_subplot(1, 1, 1, projection=proj)\n",
    "main_ax.set_extent([minlon, maxlon, minlat, maxlat], crs=proj)\n",
    "main_ax.gridlines(draw_labels=True)\n",
    "main_ax.coastlines()\n",
    "\n",
    "request = cimgt.OSM()\n",
    "main_ax.add_image(request, 12)\n",
    "\n",
    "# Coordinates of the station we were measuring windspeed\n",
    "cham_lon, cham_lat = (6.8599, 45.9259)\n",
    "passy_lon, passy_lat = (6.7, 45.9159)\n",
    "\n",
    "# Inset axe it with a fixed size\n",
    "wrax_cham = inset_axes(\n",
    "    main_ax,\n",
    "    width=1,  # size in inches\n",
    "    height=1,  # size in inches\n",
    "    loc=\"center\",  # center bbox at given position\n",
    "    bbox_to_anchor=(cham_lon, cham_lat),  # position of the axe\n",
    "    bbox_transform=main_ax.transData,  # use data coordinate (not axe coordinate)\n",
    "    axes_class=windrose.WindroseAxes,  # specify the class of the axe\n",
    ")\n",
    "\n",
    "# Inset axe with size relative to main axe\n",
    "height_deg = 0.1\n",
    "wrax_passy = inset_axes(\n",
    "    main_ax,\n",
    "    width=\"100%\",  # size in % of bbox\n",
    "    height=\"100%\",  # size in % of bbox\n",
    "    # loc=\"center\",  # don\"t know why, but this doesn\"t work.\n",
    "    # specify the center lon and lat of the plot, and size in degree\n",
    "    bbox_to_anchor=(\n",
    "        passy_lon - height_deg / 2,\n",
    "        passy_lat - height_deg / 2,\n",
    "        height_deg,\n",
    "        height_deg,\n",
    "    ),\n",
    "    bbox_transform=main_ax.transData,\n",
    "    axes_class=windrose.WindroseAxes,\n",
    ")\n",
    "\n",
    "wrax_cham.bar(wd, ws)\n",
    "wrax_passy.bar(wd, ws)\n",
    "for ax in [wrax_cham, wrax_passy]:\n",
    "    ax.tick_params(labelleft=False, labelbottom=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Subplots\n",
    "\n",
    "[seaborn](https://seaborn.pydata.org/index.html) offers an easy way to create subplots per parameter. For example per month or day. You can adapt this to have years as columns and rows as months or vice versa."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "from windrose import WindroseAxes, plot_windrose\n",
    "\n",
    "wind_data = pd.DataFrame(\n",
    "    {\n",
    "        \"ws\": np.random.random(1200) * 6,\n",
    "        \"wd\": np.random.random(1200) * 360,\n",
    "        \"month\": np.repeat(range(1, 13), 100),\n",
    "    }\n",
    ")\n",
    "\n",
    "\n",
    "def plot_windrose_subplots(data, *, direction, var, color=None, **kwargs):\n",
    "    \"\"\"wrapper function to create subplots per axis\"\"\"\n",
    "    ax = plt.gca()\n",
    "    ax = WindroseAxes.from_ax(ax=ax)\n",
    "    plot_windrose(direction_or_df=data[direction], var=data[var], ax=ax, **kwargs)\n",
    "\n",
    "\n",
    "# this creates the raw subplot structure with a subplot per value in month.\n",
    "g = sns.FacetGrid(\n",
    "    data=wind_data,\n",
    "    # the column name for each level a subplot should be created\n",
    "    col=\"month\",\n",
    "    # place a maximum of 3 plots per row\n",
    "    col_wrap=3,\n",
    "    subplot_kws={\"projection\": \"windrose\"},\n",
    "    sharex=False,\n",
    "    sharey=False,\n",
    "    despine=False,\n",
    "    height=3.5,\n",
    ")\n",
    "\n",
    "g.map_dataframe(\n",
    "    plot_windrose_subplots,\n",
    "    direction=\"wd\",\n",
    "    var=\"ws\",\n",
    "    normed=True,\n",
    "    # manually set bins, so they match for each subplot\n",
    "    bins=(0.1, 1, 2, 3, 4, 5),\n",
    "    calm_limit=0.1,\n",
    "    kind=\"bar\",\n",
    ")\n",
    "\n",
    "# make the subplots easier to compare, by having the same y-axis range\n",
    "y_ticks = range(0, 17, 4)\n",
    "for ax in g.axes:\n",
    "    ax.set_legend(\n",
    "        title=r\"$m \\cdot s^{-1}$\", bbox_to_anchor=(1.15, -0.1), loc=\"lower right\"\n",
    "    )\n",
    "    ax.set_rgrids(y_ticks, y_ticks)\n",
    "\n",
    "# adjust the spacing between the subplots to have sufficient space between plots\n",
    "plt.subplots_adjust(wspace=-0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Functional API"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Instead of using object oriented approach like previously shown, some\n",
    "\"shortcut\" functions have been defined: `wrbox`, `wrbar`,\n",
    "`wrcontour`, `wrcontourf`, `wrpdf`. See [unit tests](https://github.com/python-windrose/windrose/blob/master/tests/test_windrose.py)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pandas support"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "windrose not only supports Numpy arrays. It also supports also Pandas\n",
    "DataFrame. `plot_windrose` function provides most of plotting features\n",
    "previously shown."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "N = 500\n",
    "ws = np.random.random(N) * 6\n",
    "wd = np.random.random(N) * 360\n",
    "df = pd.DataFrame({\"speed\": ws, \"direction\": wd})\n",
    "plot_windrose(df, kind=\"contour\", bins=np.arange(0, 8, 1), cmap=cm.hot, lw=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mandatory:\n",
    "\n",
    "- `df`: Pandas DataFrame with `DateTimeIndex` as index\n",
    "  and at least 2 columns (`'speed'` and `'direction'`).\n",
    "\n",
    "Optional:\n",
    "\n",
    "- `kind` : kind of plot (might be either, `'contour'`, `'contourf'`, `'bar'`, `'box'`, `'pdf'`)\n",
    "- `var_name` : name of var column name ; default value is `VAR_DEFAULT='speed'`\n",
    "- `direction_name` : name of direction column name ; default value is\n",
    "  `DIR_DEFAULT='direction'`\n",
    "- `clean_flag` : cleanup data flag (remove\n",
    "  data points with `NaN`, `var=0`) before plotting ; default value is\n",
    "  `True`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Video export\n",
    "\n",
    "A video of plots can be exported. A playlist of videos is [available here](https://www.youtube.com/playlist?list=PLE9hIvV5BUzsQ4EPBDnJucgmmZ85D_b-W), see:\n",
    "\n",
    "[![Video1](http://img.youtube.com/vi/0u2RxtGgEFo/0.jpg)](https://www.youtube.com/watch?v=0u2RxtGgEFo)\n",
    "\n",
    "[![Video2](http://img.youtube.com/vi/3CWpjSEt0so/0.jpg)](https://www.youtube.com/watch?v=3CWpjSEt0so)\n",
    "\n",
    "[![Video3](http://img.youtube.com/vi/UiGC-3aw9TM/0.jpg)](https://www.youtube.com/watch?v=UiGC-3aw9TM)\n",
    "\n",
    "[Source code](https://github.com/python-windrose/windrose/blob/master/samples/example_animate.py).\n",
    "\n",
    "This is just a sample for now. API for video need to be created.\n",
    "\n",
    "Use:\n",
    "\n",
    "```bash\n",
    "$ python samples/example_animate.py --help\n",
    "```\n",
    "\n",
    "to display command line interface usage."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
